package com.dotflat.fin.service.impl;

import com.dotflat.fin.cnst.Const;
import com.dotflat.fin.cnst.OrderEnum;
import com.dotflat.fin.cnst.ProductTypeEnum;
import com.dotflat.fin.cnst.ProductUnitEnum;
import com.dotflat.fin.domain.FinPlanOrder;
import com.dotflat.fin.domain.PayRecord;
import com.dotflat.fin.domain.Wallet;
import com.dotflat.fin.domain.WalletFlow;
import com.dotflat.fin.dto.AppPayResult;
import com.dotflat.fin.model.APPPayAttach;
import com.dotflat.fin.repository.FinPlanOrderRepository;
import com.dotflat.fin.repository.PayRecordRepository;
import com.dotflat.fin.repository.WalletFlowRepository;
import com.dotflat.fin.service.FinPlanService;
import com.dotflat.fin.service.SystemWalletFlowService;
import com.dotflat.fin.service.WalletService;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.matt.commons.exception.BusinessException;
import com.matt.domain.Clientele;
import com.matt.domain.Contract;
import com.matt.domain.ContractProduct;
import com.matt.domain.Product;
import com.matt.foundation.model.ErrorCode;
import com.matt.repository.ContractRepository;
import com.matt.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.dotflat.fin.cnst.OrderEnum.PayStatusEnum.PAIED;

@Service
@Slf4j
public class PayServiceProxy {

    @Autowired
    private PayRecordRepository payRecordRepository;

    @Autowired
    private FinPlanOrderRepository orderRepository;

    @Autowired
    private ContractRepository contractRepository;

    @Autowired
    private ContractService contractService;

    @Autowired
    private ClienteleService clienteleService;

    @Autowired
    private WalletFlowRepository walletFlowRepository;

    @Autowired
    private WalletService walletService;

    @Autowired
    private SystemWalletFlowService systemWalletFlowService;

    @Autowired
    private TeachCallService teachCallService;

    @Autowired
    private FinPlanService finPlanService;

    @Autowired
    private ContractProductService contractProductService;

    @Autowired
    private ProductService productService;

    @Transactional(rollbackOn = Exception.class)
    public String processContractPayment(String payType, APPPayAttach p, String transactionId, String outTradeNo, Long totalFee, AppPayResult payResult){

        //outTradeNo 就是支付记录的Id， 查找发起的支付记录
        PayRecord payRecord = payRecordRepository.getOne(outTradeNo);
        if (payRecord == null){
            log.warn("回调订单不存在");
            return WxPayNotifyResponse.success("支付成功！");
        }

        // 检查这个订单是否已经处理过
        if (payRecord.getPayTime() != null || payRecord.getPayStatus() == PAIED.getId()) {
            return WxPayNotifyResponse.success("订单已经处理成功!");
        }

        payRecord.setPayTime(new Date());
        payRecord.setPayId(transactionId);
        payRecord.setPayResult(payResult);

        String payChannelVal = "未知支付方式";
        if (payType.equals("wechat")){
            payChannelVal = "微信支付";
        }else if(payType.equals("alipay")){
            payChannelVal = "支付宝支付";
        }else{

        }

        // 账单状态变更
        if (StringUtils.isEmpty(payRecord.getPayOrderId())) {  //其他支付方案
            //扣减余额支付的余额
            processWalletBalance(payRecord);

            //创建流水
            Clientele client = clienteleService.getById(payRecord.getCreatedBy());
            String title = "";
            if (p.getResourceType() == Const.RES_TYPE.PHOTOPRINT.codeOf()){
                title = "相册打印";
            }

            generateFlow(client, title, payRecord);

            //更新支付记录
            updatePayRecord(payRecord, transactionId, outTradeNo, totalFee, OrderEnum.PayTypeEnum.WXPAY.getKey());


            //发送微信模板消息
            teachCallService.notifyPayOrder(client.getAreaId(), payRecord.getCreatedBy(),
                    client.getChildName(), client.getStaffName(), title,
                    payRecord.getTotalFee().toString(), payChannelVal, p.getResourceType(), p.getResourceId());

            return WxPayNotifyResponse.success("支付成功！");
        }

        return finishClassicPayment(payRecord, payType, p, transactionId, outTradeNo, totalFee, payChannelVal);
    }

    public String finishClassicPayment(PayRecord payRecord, String payType, APPPayAttach p, String transactionId, String outTradeNo, Long totalFee, String payChannelVal) {


        System.out.println("进入支付==========");
        FinPlanOrder order = orderRepository.getOne(payRecord.getPayOrderId());
        if (order == null) {
            return WxPayNotifyResponse.fail("支付对象不存在 sn=" + outTradeNo);
        }

        if (order.getPayStatus() != Const.PAY_STATUS.PAIED.codeOf()){
            order.setPayStatus(Const.PAY_STATUS.PAIED.codeOf());
            order.setPayType(payType);
            order.setPaiedTime(new Date());
            orderRepository.save(order);
            System.out.println("修改状态成功==========");
        }

        //扣减余额支付的余额
        processWalletBalance(payRecord);

        //更新合同
        //处理合同支付状态
        Contract contract = contractRepository.getOne(order.getContractId());

        contract.setPracticalAmount(new BigDecimal(order.getTotalAmount()));

        contractService.processContractStatus(contract, new Date()); //这个里面有contract 保存逻辑

        //创建支付历史
        contractService.processContractPayHistory(contract, payChannelVal, null, "  支付账单：" + order.getTitle());

        //处理教务系统逻辑
        contractService.beginTeachRoll(contract);

        //创建流水
        Clientele client = clienteleService.getById(contract.getClienteleId());
        generateFlow(client, order.getTitle(), payRecord);

        //更新支付记录
        updatePayRecord(payRecord, transactionId, outTradeNo, totalFee, OrderEnum.PayTypeEnum.WXPAY.getKey());

        System.out.println("支付记录修改成功==========");
        //增加摄像头时间
        updateCamera(order);

        //计算定金
        updateDeposit(client, order);

        //发送微信模板消息
        teachCallService.notifyPayOrder(client.getAreaId(), contract.getClienteleId(),
                order.getChildName(), order.getCreatedBy(), order.getTitle(),
                order.getTotalAmount().toString(), payChannelVal, p.getResourceType(), p.getResourceId());

        //更新计数器
        finPlanService.updateFinPlanCount(order.getPlanId(), false, true);

        return WxPayNotifyResponse.success("支付成功！");
    }

    protected void processWalletBalance(PayRecord payRecord){
        if (payRecord.getUseDeposit() != null && payRecord.getUseDeposit() > 0) {
            Clientele clientele = clienteleService.getById(payRecord.getAreaId(), payRecord.getCreatedBy());
            Wallet wallet = walletService.queryWalletByClientele(clientele);

            if (payRecord.getUseDeposit() > wallet.getBalance()) {
                //扣减金额大于余额
                throw new BusinessException(ErrorCode.CONTRACT_MONEY_ERROR, "余额不足");
            }else {
                wallet.setBalance(wallet.getBalance() - payRecord.getUseDeposit());
            }

            walletService.update(wallet);
        }
    }

    protected void generateFlow(Clientele clientele, String title, PayRecord payRecord){

        //更新钱包金额信息
        Wallet wallet = walletService.queryWalletByClientele(clientele);
        if(wallet !=null){
            //处理用户钱包总消费
            wallet.setFullAmount(wallet.getFullAmount() + payRecord.getTotalFee());
            walletService.update(wallet);
        }

        //创建用户钱包流水信息
        WalletFlow walletFlow = WalletFlow.of(wallet.getId(), clientele.getId(),
                Const.FLOW_SOURCE_TYPE.CASH.codeOf(),  Const.FLOW_TYPE.INCOME.codeOf(), payRecord.getTotalFee(), title);
        //设置园区信息
        walletFlow.setAreaId(clientele.getAreaId());

        walletFlowRepository.save(walletFlow);

        //创建管理平台钱包流水信息
        systemWalletFlowService.generateIncomeFlow(clientele, title, payRecord.getCreated(),
                Const.FLOW_SOURCE_TYPE.CASH,
                payRecord.getTotalFee());
    }

    /**
     * 支付成功，更新订单数据
     * @param
     * @param  payType
     */
    @Async
    public void  updatePayRecord(PayRecord payRecord, String payId, String orderSn, Long amount, String payType){

        long paiedMoney = payRecord.getPaiedMoney();//已支付金额

        //更新项目金额信息
        payRecord.setPaiedMoney( paiedMoney + amount );

        payRecord.setPayTime(new Date());
        payRecord.setPayStatus(PAIED.getId());

        payRecord.setPayType(payType);
        payRecord.setPayId(payId);

//        payRecord.setOutTradeNo(orderSn);

        payRecordRepository.save(payRecord);
    }

    /**
     * 处理定金
     * @param order
     */
    @Async
    public void updateDeposit(Clientele clientele, FinPlanOrder order){
        List<ContractProduct> contractProducts = contractProductService.findByContractId(order.getContractId());

        if (contractProducts.size() == 0){
            return;
        }

        BigDecimal depositAmount = BigDecimal.valueOf(0);
        for (ContractProduct cp : contractProducts){
            if (cp.getProductType() != ProductTypeEnum.DEPOSIT.getCode()){
                continue;
            }
            depositAmount = depositAmount.add(cp.getPracticalTotalAmount());
        }

        //更新钱包金额信息
        long amount = (long)(depositAmount.doubleValue() * 100);
        Wallet wallet = walletService.queryWalletByClientele(clientele);
        if(wallet !=null){
            //处理用户钱包充值和余额
            wallet.setDeposit(wallet.getDeposit() + amount);
            wallet.setBalance(wallet.getBalance() + amount);
            walletService.update(wallet);
        }

        //创建用户钱包流水信息
        WalletFlow walletFlow = WalletFlow.of(wallet.getId(), clientele.getId(),
                Const.FLOW_SOURCE_TYPE.DEPOSIT.codeOf(),  Const.FLOW_TYPE.INCOME.codeOf(), amount, "定金充值");
        //设置园区信息
        walletFlow.setAreaId(clientele.getAreaId());

        walletFlowRepository.save(walletFlow);
     }

    /**
     * 支付成功，增加摄像头时间
     * @param
     */
    @Async
    public void updateCamera(FinPlanOrder order){
        List<ContractProduct> contractProducts = contractProductService.findByContractId(order.getContractId());

        if (contractProducts.size() == 0){
            return;
        }

        List<String> cameraItemIds = contractProducts.stream()
                .filter(o->o.getProductType()== ProductTypeEnum.CAMERA.getCode())
                .map(o->o.getProductId())
                .collect(Collectors.toList());

        List<Product> cameraProducts = productService.findAllByIds(order.getAreaId(), cameraItemIds);
        Map<String, Product> cameraCache = cameraProducts.stream().collect(Collectors.toMap(Product::getId, o->o));

        contractProducts.stream()
                .filter(o->o.getProductType()== ProductTypeEnum.CAMERA.getCode())
                .forEach(o->{
                    Product p = cameraCache.get(o.getProductId());

                    ProductUnitEnum unit = ProductUnitEnum.get(p.getUnit());

                    if (unit == null){
                        try{
                            unit = ProductUnitEnum.valueOf(p.getUnit());
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }

                    if (unit != null){
                        teachCallService.addCameraTime(contractProducts.get(0).getClienteleId(),
                                unit.getMonth() * ((int)(double)o.getCount()),
                                unit.getDay() * ((int)(double)o.getCount()));
                    }else {
                        teachCallService.addCameraTime(contractProducts.get(0).getClienteleId(), 1, 0);
                    }
                });
    }

}
